package com.liujun.io.nio.mysql.bean.protocol;

import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

import com.liujun.io.nio.mysql.protocol.comm.BufferUtil;
import com.liujun.io.nio.mysql.protocol.comm.SecurityUtil;
import com.liujun.io.nio.mysql.protocol.cosole.Capabilities;
import com.liujun.io.nio.mysql.protocol.inf.DataParseInf;

public class AuthPackageBean extends PackageHeader implements DataParseInf<AuthPackageBean> {

    /**
     * 客户端权能标志：用于与客户端协商通讯方式，
     * 标志位含义与握手初始化报文中的相同。客户端收到服务器发来的初始化报文后，
     * 会对服务器发送的权能标志进行修改，保留自身所支持的功能，然后将权能标返回给服务器，
     * 从而保证服务器与客户端通讯的兼容性。
    * @字段说明 protocolVersion
    */
    private long clientFlag;

    /**
     * 最大消息长度：客户端发送请求报文时所支持的最大消息长度值。一般为16M
    * @字段说明 maxPackageLong
    */
    private long maxPackageLong = 16 * 1024 * 1024;

    /**
     * 字符编码：标识通讯过程中使用的字符编码，与服务器在认证初始化报文中发送的相同。
    * @字段说明 charSetIndex
    */
    private int charSetIndex;

    /**
     * 填充值,一般长度23
    * @字段说明 fillbyte
    */
    private byte[] fillbyte;

    /**
     * 填充值值信息
    * @字段说明 FILLER
    */
    private static final byte[] FILLER = new byte[23];

    /**
     * 用户名：客户端登陆用户的用户名称。
    * @字段说明 userName
    */
    private String userName;

    /**
     * 挑战认证数据：客户端用户密码使用服务器发送的挑战随机数进行加密后，
     * 生成挑战认证数据，然后返回给服务器，用于对用户身份的认证。
    * @字段说明 passwd
    */
    private byte[] passwd;

    /**
     * 数据库名称：当客户端的权能标志位 CLIENT_CONNECT_WITH_DB 被置位时，该字段必须出现。
    * @字段说明 dataBase
    */
    private String dataBase;

    /**
     * 进行客户端的权能标识
    * 方法描述
    * @return
    * @创建日期 2016年12月13日
    */
    private static long initClientFlags() {
        int flag = 0;
        flag |= Capabilities.CLIENT_LONG_PASSWORD;
        flag |= Capabilities.CLIENT_FOUND_ROWS;
        flag |= Capabilities.CLIENT_LONG_FLAG;
        flag |= Capabilities.CLIENT_CONNECT_WITH_DB;
        // flag |= Capabilities.CLIENT_NO_SCHEMA;
        boolean usingCompress = false;
        if (usingCompress) {
            flag |= Capabilities.CLIENT_COMPRESS;
        }
        flag |= Capabilities.CLIENT_ODBC;
        flag |= Capabilities.CLIENT_LOCAL_FILES;
        flag |= Capabilities.CLIENT_IGNORE_SPACE;
        flag |= Capabilities.CLIENT_PROTOCOL_41;
        flag |= Capabilities.CLIENT_INTERACTIVE;
        // flag |= Capabilities.CLIENT_SSL;
        flag |= Capabilities.CLIENT_IGNORE_SIGPIPE;
        flag |= Capabilities.CLIENT_TRANSACTIONS;
        // flag |= Capabilities.CLIENT_RESERVED;
        flag |= Capabilities.CLIENT_SECURE_CONNECTION;
        // client extension
        flag |= Capabilities.CLIENT_MULTI_STATEMENTS;
        flag |= Capabilities.CLIENT_MULTI_RESULTS;
        return flag;
    }

    @Override
    public AuthPackageBean readPackage(ByteBuffer buffer) {
        return null;
    }

    private static byte[] passwd(String pass, HandshakeBean hs) throws NoSuchAlgorithmException {
        if (pass == null || pass.length() == 0) {
            return null;
        }
        byte[] passwd = pass.getBytes();
        int sl1 = hs.challengeRandom.length;
        int sl2 = hs.restOfScrambleBuff.length;
        byte[] seed = new byte[sl1 + sl2];
        System.arraycopy(hs.challengeRandom, 0, seed, 0, sl1);
        System.arraycopy(hs.restOfScrambleBuff, 0, seed, sl1, sl2);
        return SecurityUtil.scramble411(passwd, seed);
    }

    @Override
    public int getpackageSize() {
        int size = 0;
        // 添加，客户端标识
        size = size + 4;
        // 包大小
        size = size + 4;
        // 1位字符编码
        size = size + 1;
        // 填充值
        size = size + 23;
        // 用户名
        size = size + ((userName == null) ? 1 : userName.length() + 1);
        // 添加密码
        size = size + ((passwd == null) ? 1 : BufferUtil.getLength(passwd));
        // 数据库长度
        size = size + ((dataBase == null) ? 1 : dataBase.length() + 1);
        return size;
    }

    @Override
    public ByteBuffer getWriteToPackage(Map<String, Object> param) {
        // 设置当前的包顺序为1
        this.seq = 1;
        // 设置客户端的标识
        this.clientFlag = initClientFlags();
        // 设置最大包,已经默认
        // this.maxPackageLong =
        // 字符编码
        this.charSetIndex = 0;
        // 设置用户
        this.userName = "root";
        // 设置密码
        try {
            this.passwd = passwd("liujun", (HandshakeBean) param.get("handShakeBean"));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 设置数据库
        this.dataBase = "db1";

        int pkgSize = this.getpackageSize();
        // 4,字节为包头的大小
        ByteBuffer resultByte = ByteBuffer.allocate(pkgSize + 4);

        // 进行包大小的数据写入
        BufferUtil.writeUB3(resultByte, pkgSize);
        // 写入包在id
        resultByte.put(seq);
        // 写入客户端标识
        BufferUtil.writeUB4(resultByte, clientFlag);
        // 写入最大包
        BufferUtil.writeUB4(resultByte, maxPackageLong);
        // 写入字符编码
        resultByte.put((byte) charSetIndex);
        // 写入填充值
        resultByte.put(FILLER);
        // 写入用户名
        if (null == userName) {
            resultByte.put((byte) 0);
        } else {
            byte[] userData = userName.getBytes();
            BufferUtil.writeWithNull(resultByte, userData);
        }

        // 写入密码
        if (null == passwd) {
            resultByte.put((byte) 0);
        } else {
            BufferUtil.writeWithLength(resultByte, passwd);
        }

        // 写入dataBase
        if (null == dataBase) {
            resultByte.put((byte) 0);
        } else {
            byte[] dataBaseBytes = dataBase.getBytes();
            BufferUtil.writeWithNull(resultByte, dataBaseBytes);
        }

        return resultByte;

    }

}
